home *** CD-ROM | disk | FTP | other *** search
/ Gekkan Dennou Club 145 / Gekkan Dennou Club - 2000.6 Vol. 145 (Japan).7z / Gekkan Dennou Club - 2000.6 Vol. 145 (Japan) (Track 1).bin / tools / sharp / sxwork3.lzh / サンプル応用編 / イメージ編集 / GIMAGE.C next >
Text File  |  1994-03-10  |  22KB  |  698 lines

  1. /******************************************************************************
  2.  *    gimage.c:    イメージ編集の処理関数
  3.  ******************************************************************************
  4.  *    Workroom SX-68K Sample Program Copyright 1994 SHARP
  5.  */
  6. #include <stdlib.h>
  7. #include <sxmemory.h>        /* メモリマンを利用するときに必要    */
  8. #include <event.h>        /* イベントマンを利用するときに必要    */
  9. #include <sxgraph.h>        /* グラフ系マネージャを利用するときに必要 */
  10. #include <control.h>        /* コントロールマンを利用するときに必要    */
  11. #include <dialog.h>        /* ダイアログマンを利用するときに必要    */
  12. #include "gimage.h"        /* このプログラム固有のヘッダファイル    */
  13.  
  14. /******************************************************************************
  15.  *    paintPen():    ペンでのペイント処理
  16.  ******************************************************************************
  17.  *    引数:    ComVal *pcv    共通変数へのポインタ
  18.  *        LPoint lpt    マウスレフトダウン時の座標
  19.  */
  20. void paintPen(ComVal *pcv, LPoint lpt)
  21. {
  22.     Point npt, opt, penSize[2];
  23.     Rect rc;
  24.  
  25.     GMPenSize(pcv->penSize.x_y);    /* ペンサイズを設定する        */
  26.     /* フォアグラウンドカラーを選択中のパレット番号にする */
  27.     GMForeColor(pcv->paletNo);
  28.     rc.l.l_t = lpt;
  29.     rc.l.r_b = lpt;
  30.     drawFig(pcv, &rc);        /* マウスの押された場所を描画する */
  31.     GMMove(lpt);            /* ペンの座標の初期値を設定する */
  32.  
  33.     /* ビッツを使用するためにメモリをロックする */
  34.     GMLockBits(pcv->offBitsHdl);
  35.  
  36.     /* オフスクリーン用グラフをカレントグラフにする */
  37.     GMSetGraph(&pcv->offGraph);
  38.     pcv->offGraph.bmap = &(*pcv->offBitsHdl)->bmap;
  39.  
  40.     GMPenSize(pcv->penSize.x_y);    /* ペンサイズを設定する        */
  41.     /* フォアグラウンドカラーを選択中のパレット番号にする */
  42.     GMForeColor(pcv->paletNo);
  43.     GMPenMode(G_PSET);        /* ペンモードをPSETにする    */
  44.     drawFig(pcv, &rc);        /* マウスの押された場所を描画する */
  45.     GMMove(lpt);            /* ペンの座標の初期値を設定する */
  46.  
  47.     penSize[0] = pcv->penSize;
  48.     penSize[1].x_y = 0;
  49.     npt.x_y = lpt;
  50.     opt.x_y = lpt;
  51.     while (EMLStill()) {
  52.         /* マウスが移動された場合のみ直線を描画する */
  53.         if (opt.x_y != npt.x_y) {
  54.             /* オフスクリーン用グラフをカレントグラフにする */
  55.             GMSetGraph(&pcv->offGraph);
  56.             pcv->offGraph.bmap = &(*pcv->offBitsHdl)->bmap;
  57.  
  58.             /* ウィンドウの範囲になるよう調節する */
  59.             ajustPoint(&npt, penSize);
  60.             /* オフスクリーンに描画する */
  61.             GMLine(npt.x_y);
  62.             /* メインウィンドウをグラフィックタイプでカレントグラフ
  63.                にする */
  64.             setGraph(pcv, MAIN, G_GRP);
  65.  
  66.             /* メインウィンドウに描画する */
  67.             GMLine(npt.x_y);
  68.         }
  69.         opt = npt;
  70.         /* メインウィンドウをカレントグラフにする */
  71.         GMSetGraph(&pcv->windowPtr->graph);
  72.  
  73.         /* マウスの現在位置を取得する */
  74.         npt.x_y = EMMSLoc();
  75.     }
  76.     /* ビッツのメモリをアンロックする */
  77.     GMUnlockBits(pcv->offBitsHdl);
  78. }
  79.  
  80. /******************************************************************************
  81.  *    paintRgn():    リージョンでのペイント処理
  82.  ******************************************************************************
  83.  *    引数:    ComVal *pcv    共通変数へのポインタ
  84.  *        LPoint lpt    マウスレフトダウン時の座標
  85.  */
  86. void paintRgn(ComVal *pcv, LPoint lpt)
  87. {
  88.     int ct;
  89.     unsigned long ClickTime;
  90.     unsigned long DblClickT;
  91.     Point npt, opt, bpt, wpt;
  92.     Rect rc;
  93.     Event ev;
  94.  
  95.     struct {
  96.         Point pt[500];        /* ラバーバンドペンサイズ    */
  97.     } **hRgn;
  98.  
  99.     GMPenSize(pcv->penSize.x_y);    /* ペンサイズを設定する        */
  100.     /* フォアグラウンドカラーをパレット番号の15にする */
  101.     GMForeColor(15);
  102.     GMPenMode(G_XOR);        /* ペンモードをXORにする    */
  103.     DblClickT = EMDClickGet();    /* ダブルクリックの既定値を取得する */
  104.     /* マウスレフトダウンイベント発生時の時間をセットする */
  105.     ClickTime = pcv->event.ts.when;
  106.  
  107.     /* リージョンの座標データ用ハンドルを確保する */
  108.     hRgn = MMChHdlNew(2048);
  109.     if (hRgn == NULL) {
  110.         DMError(D_CONFIRM, "メモリが確保できません。");
  111.         return;
  112.     }
  113.  
  114.     /* ラバーバンドのための初期のレクタングルを設定する */
  115.     rc.l.l_t = lpt;
  116.     rc.l.r_b = lpt;
  117.     drawFig(pcv, &rc);        /* ラバーバンドを描画する    */
  118.     ct = 0;
  119.     (*hRgn)->pt[ct++].x_y = lpt;
  120.     opt.x_y = lpt;
  121.     npt.x_y = lpt;
  122.     wpt.x_y = lpt;
  123.     bpt.x_y = lpt;
  124.  
  125.     while (1) {
  126.         /* イベントキューからすべてのイベントを取り出す。そうしないと、
  127.            イベントが溜まって途中でマウスレフトダウンイベントが受け取れ
  128.            なくなる */
  129.         if (EMGet(EM_EVERY, &ev) && ev.what == E_MSLDOWN) {
  130.             /* マウスレフトダウンイベントがあったとき */
  131.             if (ev.when <= ClickTime + DblClickT
  132.              && (*hRgn)->pt[ct - 1].x_y == npt.x_y && ct >= 3) {
  133.                 /* ダブルクリックでかつクリック座標が前回クリッ
  134.                    クされた座標と違っていて3点以上入力されてい
  135.                    たならリージョン座標のセットを終了する */
  136.                 drawFig(pcv, &rc); /* 最後の仮表示を消去する */
  137.                 break;
  138.             } else {
  139.                 /* マウスレフトダウンイベント発生時の時間を
  140.                    設定する */
  141.                 ClickTime = ev.when;
  142.                 (*hRgn)->pt[ct++] = wpt;
  143.                 rc.l.l_t = wpt.x_y;
  144.                 bpt = wpt;
  145.                 if (ct >= 512) {
  146.                     DMError(D_CONFIRM, "これ以上座標は指定できません。\r"
  147.                                "多角形の登録を終了します。");
  148.                     break;
  149.                 }
  150.                 drawFig(pcv, &rc);
  151.             }
  152.             /* 先行するマウスレフトアップイベントを取り除く(これが
  153.                ないと、途中でマウスダウンイベントが拾えなくなる)*/
  154.             EMLWait();
  155.         }
  156.         /* マウスが移動された場合のみラバ-バンドを描画する */
  157.         if (opt.x_y != npt.x_y) {
  158.             /* 前回のラバーバンドを消して */
  159.             drawFig(pcv, &rc);
  160.             wpt = npt;
  161.             /* ウィンドウ内におさまるように座標を調整する */
  162.             ajustEndPoint(bpt.x_y, &wpt);
  163.             rc.l.r_b = wpt.x_y;
  164.             /* 再度ラバーバンドを描画する */
  165.             drawFig(pcv, &rc);
  166.         }
  167.  
  168.         opt = npt;
  169.         /* マウスの現在位置を取得する */
  170.         npt.x_y = EMMSLoc();
  171.     }
  172.  
  173.     /* ビッツを使用するためにメモリをロックする */
  174.     GMLockBits(pcv->offBitsHdl);
  175.  
  176.     /* データよりリージョンを作成しオフスクリーンに描画する */
  177.     if (!makeRgn(pcv, (*hRgn)->pt, ct, &rc)) {
  178.         /* ビッツのメモリをアンロックする */
  179.         GMUnlockBits(pcv->offBitsHdl);
  180.         return;
  181.     }
  182.  
  183.     /* メインウィンドウをグラフィックタイプでカレントグラフにする */
  184.     setGraph(pcv, MAIN, G_GRP);
  185.  
  186.     /* オフスクリーンからコピーして描画する */
  187.     GMTransImg(&(*pcv->offBitsHdl)->bmap, pcv->windowPtr->graph.bmap, &rc, &rc);
  188.  
  189.     /* ビッツのメモリをアンロックする */
  190.     GMUnlockBits(pcv->offBitsHdl);
  191.  
  192.     /* リージョンの座標データ用ハンドルを解放する */
  193.     MMHdlDispose(hRgn);
  194. }
  195.  
  196. /******************************************************************************
  197.  *    makeRgn():    リージョン図形の登録および描画処理
  198.  ******************************************************************************
  199.  *    引数:    ComVal *pcv    共通変数へのポインタ
  200.  *        Point *ptt    リージョン用の座標テーブルへのポインタ
  201.  *        int ct        リージョン用の座標の個数
  202.  *        Rect *prcrgn    作成されたリージョンを囲むレクタングルへのポインタ
  203.  *    戻り値:    BOOLEAN        = TRUE:  正常終了
  204.  *                = FALSE: 異常終了
  205.  *    注釈:    与えられたデータからリージョン図形の作成および描画を行う。
  206.  */
  207. BOOLEAN makeRgn(ComVal *pcv, Point *ptt, int ct, Rect *prcrgn)
  208. {
  209.     int i, errCode;
  210.     Region **rgnHdl;
  211.  
  212.     /* リージョンの仮表示の消去を行う */
  213.     /* 表示位置をデータの先頭に設定する */
  214.     GMMove(ptt[0].x_y);
  215.     /* データを元に仮表示を消去する */
  216.     for (i = 1; i < ct; i++)
  217.         GMLine(ptt[i].x_y);
  218.  
  219.     /* 待ち状態を示すマウスポインタを表示する */
  220.     EMEnCross();
  221.     /* オフスクリーン用グラフをカレントグラフにする */
  222.     GMSetGraph(&pcv->offGraph);
  223.     pcv->offGraph.bmap = &(*pcv->offBitsHdl)->bmap;
  224.  
  225.     /* フォアグラウンドカラーを選択中のパレット番号にする */
  226.     GMForeColor(pcv->paletNo);
  227.     GMBackColor(0);
  228.     /* ペンモードをPSETにする */
  229.     GMPenMode(G_PSET);
  230.     GMPenSize(pcv->penSize.x_y);    /* ペンサイズを設定する        */
  231.  
  232.     /* 空のリージョンを作成する */
  233.     rgnHdl = GMNewRgn();
  234.     if (rgnHdl == NULL) {
  235.         /* 待ち状態を示すマウスポインタを元に戻す */
  236.         EMDeCross();
  237.         DMError(D_CONFIRM, "メモリが確保できません。");
  238.         return FALSE;
  239.     }
  240.     /* リージョンの記録開始 */
  241.     GMOpenRgn();
  242.     /* 表示位置をデータの先頭に設定する */
  243.     GMMove(ptt[0].x_y);
  244.     /* リージョン図形の記録を行う */
  245.     for (i = 1; i < ct; i++)
  246.         GMLine(ptt[i].x_y);
  247.     /* 始点データと結ぶ */
  248.     GMLine(ptt[0].x_y);
  249.     /* リージョンの記録終了 */
  250.     errCode = GMCloseRgn(rgnHdl);
  251.     if (errCode < 0) {
  252.         GMDisposeRgn(rgnHdl);    /* リージョンハンドルを解放する    */
  253.         /* 待ち状態を示すマウスポインタを元に戻す */
  254.         EMDeCross();
  255.         DMError(D_CONFIRM, "メモリが不足しています。\r"
  256.                    "リージョンの記録ができません。");
  257.         return FALSE;
  258.     }
  259.     /* リージョンを囲むレクタングルの座標をcomDataのboundsに設定する */
  260.     *prcrgn = (*rgnHdl)->bounds;
  261.  
  262.     /* 入力されたリージョンをオフスクリーンに描画する */
  263.     if (pcv->toolKind == 5)
  264.         GMFrameRgn(rgnHdl);
  265.     else
  266.         GMFillRgn(rgnHdl);
  267.  
  268.     GMDisposeRgn(rgnHdl);        /* リージョンハンドルを解放する    */
  269.     /* 待ち状態を示すマウスポインタを元に戻す */
  270.     EMDeCross();
  271.     return TRUE;
  272. }
  273.  
  274. /******************************************************************************
  275.  *    paintBrush():    ブラシでのペイント処理
  276.  ******************************************************************************
  277.  *    引数:    ComVal *pcv    共通変数へのポインタ
  278.  *        LPoint lpt    マウスレフトダウン時の座標
  279.  */
  280. void paintBrush(ComVal *pcv, LPoint lpt)
  281. {
  282.     Point npt, opt;
  283.     Rect rc;
  284.     Region **rgnHdl;
  285.  
  286.     /* 使用するリージョンハンドルを取得する */
  287.     rgnHdl = GMNewRgn();
  288.     if (rgnHdl == NULL) {
  289.         DMError(D_CONFIRM, "メモリが確保できません。");
  290.         return;
  291.     }
  292.  
  293.     /* ビッツを使用するためにメモリをロックする */
  294.     GMLockBits(pcv->offBitsHdl);    /* オフスクリーン用ビッツハンドル */
  295.     GMLockBits(pcv->wkBitsHdl);    /* ワーク用ビッツハンドル    */
  296.  
  297.     /* ワーク用グラフをカレントにする */
  298.     GMSetGraph(&pcv->wkGraph);
  299.     /* ビットマップをセットする */
  300.     pcv->wkGraph.bmap = &(*pcv->wkBitsHdl)->bmap;
  301.     /* ワークのビットマップにブラシ/消しゴムのビットイメージを描く */
  302.     GMPutRImg(*pcv->brushImg[(pcv->toolKind == 6) ? 0 : 1], 0);
  303.     /* ビットイメージをリージョンに変換する */
  304.     GMImgToRgn(rgnHdl, &(*pcv->wkBitsHdl)->bmap, &brSize);
  305.  
  306.     opt.x_y = lpt;
  307.     npt.x_y = lpt;
  308.     /* ブラシでペイントする */
  309.     brushing(pcv, rgnHdl, &opt, &npt, NULL);
  310.     if (pcv->toolKind == 7) {    /* 消しゴムが選択されているか?    */
  311.         /* 消しゴムのビットマップをXORで描画する */
  312.         rc.d.left = npt.p.x - 8;
  313.         rc.d.top = npt.p.y - 8;
  314.         rc.d.right = npt.p.x + 8;
  315.         rc.d.bottom = npt.p.y + 8;
  316.         drawEraser(pcv, &rc);
  317.     }
  318.     while (EMLStill()) {
  319.         /* マウスが移動された場合のみブラシで描画する */
  320.         if (opt.x_y != npt.x_y)
  321.             /* ブラシでペイントする */
  322.             brushing(pcv, rgnHdl, &opt, &npt, NULL);
  323.         opt = npt;
  324.         /* メインウィンドウをカレントグラフにする */
  325.         GMSetGraph(&pcv->windowPtr->graph);
  326.  
  327.         /* マウスの現在位置を取得する */
  328.         npt.x_y = EMMSLoc();
  329.     }
  330.     if (pcv->toolKind == 7) {    /* 消しゴムが選択されているか?    */
  331.         ajustPoint(&opt, NULL);
  332.         rc.d.left = opt.p.x - 8;
  333.         rc.d.top = opt.p.y - 8;
  334.         rc.d.right = opt.p.x + 8;
  335.         rc.d.bottom = opt.p.y + 8;
  336.         /* 消しゴムのビットイメージをXORで描画する */
  337.         drawEraser(pcv, &rc);
  338.     }
  339.  
  340.     /* ビッツのメモリをアンロックする */
  341.     GMUnlockBits(pcv->offBitsHdl);
  342.     GMUnlockBits(pcv->wkBitsHdl);
  343.  
  344.     GMDisposeRgn(rgnHdl);        /* リージョンハンドルを解放する    */
  345. }
  346.  
  347. /******************************************************************************
  348.  *    brushing():    ブラシでのペイント処理
  349.  ******************************************************************************
  350.  *    引数:    ComVal *pcv    共通変数へのポインタ
  351.  *        Region **rgnHdl    ブラシのリージョンハンドル
  352.  *        Point *popt    前回のマウスレフトダウン時の座標へのポインタ
  353.  *        Point *pnpt    今回のマウスレフトダウン時の座標へのポインタ
  354.  *        Point *psize    ペンサイズの配列へのポインタ
  355.  */
  356. void brushing(ComVal *pcv, Region **rgnHdl, Point *popt, Point *pnpt, Point *psize)
  357. {
  358.     int i;
  359.     Point dpt;
  360.     LPoint lpt;
  361.     Rect rc;
  362.     Region **rgnHdl2, **subRgnHdl;
  363.  
  364.     rgnHdl2 = GMNewRgn();
  365.     if (rgnHdl2 == NULL) {
  366.         DMError(D_CONFIRM, "メモリが確保できません。");
  367.         return;
  368.     }
  369.     subRgnHdl = GMNewRgn();
  370.     if (subRgnHdl == NULL) {
  371.         GMDisposeRgn(rgnHdl2);    /* リージョンハンドルを解放する    */
  372.         DMError(D_CONFIRM, "メモリが確保できません。");
  373.         return;
  374.     }
  375.  
  376.     /* 前回ポイントと今回ポイントの座標をウィンドウ内になるよう調節する */
  377.     ajustPoint(pnpt, psize);
  378.     ajustPoint(popt, psize);
  379.  
  380.     /* ブラシリージョンの位置を設定する */
  381.     GMMoveRgn(rgnHdl, LONGWORD(popt->p.x - 8, popt->p.y - 8));
  382.  
  383.     dpt.p.x = pnpt->p.x - popt->p.x;
  384.     dpt.p.y = pnpt->p.y - popt->p.y;
  385.     if (dpt.x_y != 0) {
  386.         GMSlidedRgn(rgnHdl2, rgnHdl, dpt.x_y);
  387.         /* サブウィンドウのリージョン部分を除いた新たなリージョンを
  388.            作成する */
  389.         /* メインウィンドウをカレントグラフにする */
  390.         GMSetGraph(&pcv->windowPtr->graph);
  391.  
  392.         lpt = GMGlobalToLocal(0);
  393.         for (i = 0; i < SUBMAX; i++) {
  394.             /* サブウィンドウのリージョンをコピーして */
  395.             GMCopyRgn(subRgnHdl, pcv->subRgnHdl[i]);
  396.             /* 座標をローカル座標系に変換する */
  397.             GMSlideRgn(subRgnHdl, lpt);
  398.             /* 新たなリージョンを求める */
  399.             GMDiffRgn(rgnHdl2, rgnHdl2, subRgnHdl);
  400.         }
  401.     } else
  402.         /* 座標に変化がない(LDOWN の初回)はDOWN時の座標に描画するだけ */
  403.         GMCopyRgn(rgnHdl2, rgnHdl);
  404.  
  405.     /* オフスクリーン用グラフをカレントグラフにする */
  406.     GMSetGraph(&pcv->offGraph);
  407.     pcv->offGraph.bmap = &(*pcv->offBitsHdl)->bmap;
  408.  
  409.     /* 消しゴムが選択されているときはカラー番号は15に固定 */
  410.     GMForeColor((pcv->toolKind == 7) ? 15 : pcv->paletNo);
  411.  
  412.     GMPenMode(G_PSET);
  413.     /* オフスクリーンにリージョンを描画する */
  414.     GMFillRgn(rgnHdl2);
  415.     /* メインウィンドウをグラフィックタイプでカレントグラフにする */
  416.     setGraph(pcv, MAIN, G_GRP);
  417.  
  418.     /* 消しゴムが選択されているときはカラー番号は15に固定 */
  419.     GMForeColor((pcv->toolKind == 7) ? 15 : pcv->paletNo);
  420.  
  421.     GMPenMode(G_PSET);
  422.     /* メインウィンドウにもリージョンを描画する */
  423.     GMFillRgn(rgnHdl2);
  424.  
  425.     if (pcv->toolKind == 7) {
  426.         rc.d.left = popt->p.x - 8;
  427.         rc.d.top = popt->p.y - 8;
  428.         rc.d.right = popt->p.x + 8;
  429.         rc.d.bottom = popt->p.y + 8;
  430.         drawEraser(pcv, &rc);
  431.         rc.d.left = pnpt->p.x - 8;
  432.         rc.d.top = pnpt->p.y - 8;
  433.         rc.d.right = pnpt->p.x + 8;
  434.         rc.d.bottom = pnpt->p.y + 8;
  435.         drawEraser(pcv, &rc);
  436.     }
  437.  
  438.     GMDisposeRgn(subRgnHdl);    /* リージョンハンドルを解放する    */
  439.     GMDisposeRgn(rgnHdl2);
  440. }
  441.  
  442. /******************************************************************************
  443.  *    drawEraser():        消しゴムの描画
  444.  ******************************************************************************
  445.  *    引数:    ComVal *pcv    共通変数へのポインタ
  446.  *        Rect *prc    消しゴムのレクタングルへのポインタ
  447.  */
  448. void drawEraser(ComVal *pcv, Rect *prc)
  449. {
  450.     /* メインウィンドウをテキストタイプでカレントグラフにする */
  451.     setGraph(pcv, MAIN, G_TXT);
  452.  
  453.     GMAPage(G_PAGE0 | G_PAGE1);    /* アクセスページを0と1ページにする */
  454.     GMPenMode(G_XOR);        /* ペンモードをXORにする    */
  455.     GMPenSize(LONGWORD(1, 1));    /* ペンサイズを(1, 1)に設定する    */
  456.  
  457.     GMForeColor(G_WHITE);        /* フォアグラウンドカラーを白にする */
  458.     GMFillRect(prc);        /* 消しゴムのレクタングルを塗りつぶす */
  459.  
  460.     GMForeColor(G_BLACK);        /* フォアグラウンドカラーを黒にする */
  461.     /* 消しゴムのレクタングルのフレームを描く */
  462.     GMFrameRect(prc);
  463.  
  464.     GMAPage(G_ALLPAGE);        /* アクセスページを全ページに戻す */
  465.     GMPenMode(G_PSET);        /* ペンモードも元に戻す        */
  466. }
  467.  
  468. /******************************************************************************
  469.  *    paintFig():    図形でのペイント処理
  470.  ******************************************************************************
  471.  *    引数:    ComVal *pcv    共通変数へのポインタ
  472.  *        LPoint lpt    マウスレフトダウン時の座標
  473.  */
  474. void paintFig(ComVal *pcv, LPoint lpt)
  475. {
  476.     int lastPM;
  477.     Point npt, opt, wpt;
  478.     Rect rc;
  479.  
  480.     lastPM = GMPenMode(G_XOR);    /* ペンモードをXORにする    */
  481.     GMPenSize(pcv->penSize.x_y);    /* ペンサイズを設定する        */
  482.     /* フォアグラウンドカラーをパレット番号の15にする */
  483.     GMForeColor(15);
  484.  
  485.     /* ラバーバンドのための初期のレクタングルを設定する */
  486.     rc.l.l_t = lpt;
  487.     rc.l.r_b = lpt;
  488.  
  489.     drawFig(pcv, &rc);        /* ラバーバンドを描画する    */
  490.     opt.x_y = lpt;
  491.     npt.x_y = lpt;
  492.     /* マウスの左ボタンが押されたままなら、ラバーバンドを移動する */
  493.     do {
  494.         npt.x_y = EMMSLoc();    /* マウスの現在位置を取得する    */
  495.         if (npt.x_y != opt.x_y) { /* マウスが移動したか?    */
  496.             drawFig(pcv, &rc); /* ラバーバンドを消去する    */
  497.             if (pcv->toolKind == 1) { /* 直線か?        */
  498.                 /* 終点を調節しセットする */
  499.                 wpt = npt;
  500.                 ajustEndPoint(lpt, &wpt);
  501.                 rc.l.r_b = wpt.x_y;
  502.             } else    /* 直線以外                */
  503.                 /* レクタングルを調節する */
  504.                 makeRect(lpt, npt.x_y, &rc);
  505.             drawFig(pcv, &rc); /* ラバーバンドを描画する    */
  506.         }
  507.         opt = npt;
  508.     } while (EMLStill());        /* 左ボタンが離されたら終わり    */
  509.     drawFig(pcv, &rc);        /* ラバーバンドを消去する    */
  510.  
  511.     GMPenMode(lastPM);        /* ペンモードを元に戻す        */
  512.     /* フォアグラウンドカラーを選択中のパレット番号にする */
  513.     GMForeColor(pcv->paletNo);
  514.     drawFig(pcv, &rc);        /* メインウィンドウに描画する    */
  515.  
  516.     /* ビッツを使用するためにメモリをロックする */
  517.     GMLockBits(pcv->offBitsHdl);
  518.  
  519.     /* オフスクリーン用グラフをカレントグラフにする */
  520.     GMSetGraph(&pcv->offGraph);
  521.     pcv->offGraph.bmap = &(*pcv->offBitsHdl)->bmap;
  522.  
  523.     /* フォアグラウンドカラーを選択中のパレット番号にする */
  524.     GMForeColor(pcv->paletNo);
  525.     /* ペンモードをPSETにする */
  526.     GMPenMode(G_PSET);
  527.     GMPenSize(pcv->penSize.x_y);    /* ペンサイズを設定する        */
  528.     /* オフスクリーンに描画する */
  529.     drawFig(pcv, &rc);
  530.  
  531.     /* ビッツのメモリをアンロックする */
  532.     GMUnlockBits(pcv->offBitsHdl);
  533. }
  534.  
  535. /******************************************************************************
  536.  *    drawFig():    実際の図形描画処理
  537.  ******************************************************************************
  538.  *    引数:    ComVal *pcv    共通変数へのポインタ
  539.  *        Rect *prc    描画するレクタングルへのポインタ
  540.  *    注釈:
  541.  *    指定した図形を描画する。多角形についてはラバーバンド描画のときのみ対応。
  542.  */
  543. void drawFig(ComVal *pcv, Rect *prc)
  544. {
  545.     switch (pcv->toolKind) {
  546.     case 0:                /* ペン                */
  547.     case 1:                /* 直線                */
  548.     case 5:                /* 多角形            */
  549.     case 11:            /* 多角形の塗りつぶし        */
  550.         /* ラインの描画を行う */
  551.         GMMove(prc->l.l_t);
  552.         GMLine(prc->l.r_b);
  553.         break;
  554.     case 2:                /* 長方形            */
  555.         GMFrameRect(prc);
  556.         break;
  557.     case 8:                /* 長方形の塗りつぶし        */
  558.         GMFillRect(prc);
  559.         break;
  560.     case 3:                /* 面取り長方形            */
  561.         GMFrameRRect(prc, pcv->radius.x_y);
  562.         break;
  563.     case 9:                /* 面取り長方形の塗りつぶし    */
  564.         GMFillRRect(prc, pcv->radius.x_y);
  565.         break;
  566.     case 4:                /* 円                */
  567.         GMFrameOval(prc);
  568.         break;
  569.     case 10:            /* 円の塗りつぶし        */
  570.         GMFillOval(prc);
  571.         break;
  572.     }
  573. }
  574.  
  575. /******************************************************************************
  576.  *    makeRect():    レクタングルの作成
  577.  ******************************************************************************
  578.  *    引数:    LPoint lpt1    第1点
  579.  *        LPoint lpt2    第2点
  580.  *        Rect *prc    2点より作成されるレクタングルへのポインタ
  581.  */
  582. void makeRect(LPoint lpt1, LPoint lpt2, Rect *prc)
  583. {
  584.     Point pt1, pt2;
  585.  
  586.     pt1.x_y = lpt1;
  587.     pt2.x_y = lpt2;
  588.  
  589.     /* pt2がウィンドウを外れていれば調節する */
  590.     ajustPoint(&pt2, NULL);
  591.  
  592.     /* pt1とpt2のX座標を比較して小さい方をpt1、大きい方をpt2に設定する */
  593.     prc->d.left = min(pt1.p.x, pt2.p.x);
  594.     prc->d.right = max(pt1.p.x, pt2.p.x);
  595.  
  596.     /* pt1とpt2のY座標を比較して小さい方をpt1、大きい方をpt2に設定する */
  597.     prc->d.top = min(pt1.p.y, pt2.p.y);
  598.     prc->d.bottom = max(pt1.p.y, pt2.p.y);
  599. }
  600.  
  601. /******************************************************************************
  602.  *    ajustPoint():    点をウィンドウ内に調節する
  603.  ******************************************************************************
  604.  *    引数:    Point *ppt    調節する点へのポインタ
  605.  *        Point *psize    ペンサイズの配列へのポインタ
  606.  *    注釈:
  607.  *    点がメインウィンドウを外れていたらウィンドウ内に調節する。
  608.  *    ペンサイズが設定されている場合のウィンドウの内側は、ウィンドウの端から
  609.  *    ペンサイズ分内側の値として考える。
  610.  */
  611. void ajustPoint(Point *ppt, Point *psize)
  612. {
  613.     Rect wsSize = { 0, 0, WIN_H, WIN_V };
  614.  
  615.     if (psize != NULL) {        /* ペンサイズが設定されているか? */
  616.         /* 左上座標はペンサイスを足した値 */
  617.         wsSize.d.left += psize[1].p.x;
  618.         wsSize.d.top += psize[1].p.y;
  619.         /* 右下座標はペンサイスを引いた値 */
  620.         wsSize.d.right -= psize[0].p.x;
  621.         wsSize.d.bottom -= psize[0].p.y;
  622.     }
  623.     /* 点がウィンドウを外れていれば調節する */
  624.     if (ppt->p.x < wsSize.d.left)
  625.         ppt->p.x = wsSize.d.left;
  626.     else if (ppt->p.x > wsSize.d.right)
  627.         ppt->p.x = wsSize.d.right;
  628.     if (ppt->p.y < wsSize.d.top)
  629.         ppt->p.y = wsSize.d.top;
  630.     else if (ppt->p.y > wsSize.d.bottom)
  631.         ppt->p.y = wsSize.d.bottom;
  632. }
  633.  
  634. /******************************************************************************
  635.  *    ajustEndPoint():    直線の終点をウィンドウ内に調節する
  636.  ******************************************************************************
  637.  *    引数:    LPoint lptb    直線の始点
  638.  *        Point *ppte    直線の終点/調整された直線の終点
  639.  *    注釈:
  640.  *    直線の終点がメインウィンドウを外れていたらウィンドウ内に調節する。
  641.  */
  642. void ajustEndPoint(LPoint lptb, Point *ppte)
  643. {
  644.     int mode = 0;
  645.     double a, b;
  646.     Point ptb;
  647.  
  648.     ptb.x_y = lptb;
  649.  
  650.     /* X軸に平行な直線かY軸に平行な直線か判断する */
  651.     if (ptb.p.x == ppte->p.x)
  652.         mode = 1;        /* Y軸に平行な直線: 例)X = 5;    */
  653.     if (ptb.p.y == ppte->p.y) {
  654.         if (mode == 1)
  655.             return;        /* 同一点であるから何もしない    */
  656.  
  657.         mode = 2;        /* X軸に平行な直線: 例)Y = 5;    */
  658.     }
  659.  
  660.     switch (mode) {
  661.     case 0:                /* X軸とY軸に平行でない直線    */
  662.         /* 直線の方程式y = ax + bのaおよびbを求める */
  663.         a = (double)(ppte->p.y - ptb.p.y) / (double)(ppte->p.x - ptb.p.x);
  664.         b = (double) ptb.p.y - a * (double) ptb.p.x;
  665.  
  666.         if (ppte->p.x < 0) {    /* X座標がウィンドウより左か?    */
  667.             ppte->p.x = 0;    /* X座標を左端の座標にする    */
  668.             ppte->p.y = (short) b; /* Y座標を調節する    */
  669.         /* X座標がウィンドウより右か? */
  670.         } else if (ppte->p.x > WIN_H) {
  671.             ppte->p.x = WIN_H; /* X座標を右端の座標にする    */
  672.             /* Y座標を調節する */
  673.             ppte->p.y = (short)(a * WIN_H + b);
  674.         }
  675.         if (ppte->p.y < 0) {    /* Y座標がウィンドウより上か?    */
  676.             ppte->p.x = (short)(-b / a); /* X座標を調節する */
  677.             ppte->p.y = 0;    /* Y座標を上端の座標にする    */
  678.         } else if (ppte->p.y > WIN_V) { /* Y座標を下端の座標にする */
  679.             /* X座標を調節する */
  680.             ppte->p.x = (short)((WIN_V - b) / a);
  681.             ppte->p.y = WIN_V; /* Y座標を下端の座標にする    */
  682.         }
  683.         break;
  684.     case 1:                /* Y軸に平行な直線        */
  685.         if (ppte->p.y < 0)    /* Y座標がウィンドウより上か?    */
  686.             ppte->p.y = 0;    /* Y座標を上端の座標にする    */
  687.         else if (ppte->p.y > WIN_V) /* Y座標がウィンドウより下か? */
  688.             ppte->p.y = WIN_V; /* Y座標を下端の座標にする    */
  689.         break;
  690.     case 2:                /* X軸に平行な直線        */
  691.         if (ppte->p.x < 0)    /* X座標がウィンドウより左か?    */
  692.             ppte->p.x = 0;    /* X座標を左端の座標にする    */
  693.         else if (ppte->p.x > WIN_H) /* X座標がウィンドウより右か? */
  694.             ppte->p.x = WIN_H; /* X座標を右端の座標にする    */
  695.         break;
  696.     }
  697. }
  698.